package gl.drawer

import org.lwjgl.opengl.GL44C.*
import org.lwjgl.system.MemoryStack

class Goraud: Drawer() {

    var program = 0
    var vertex = 0
    var buffer = 0

    private val colors = intArrayOf(
        255,   0,   0, 255,
          0, 255,   0, 255,
          0,   0, 255, 255,
         10,  10,  10, 255,
        100, 100, 100, 255,
        255, 255, 255, 255,
    )
    private val positions = floatArrayOf(
        -.90f, -.90f,
         .85f, -.90f,
        -.90f,  .85f,
         .90f, -.85f,
         .90f,  .90f,
        -.85f,  .90f
    )

    override fun initialize() {
        val vs = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(vs, goraudVertexShader)
        glCompileShader(vs)
        val fs = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(fs, goraudFragmentShader)
        glCompileShader(fs)
        program = glCreateProgram()
        glAttachShader(program, vs)
        glAttachShader(program, fs)
        glLinkProgram(program)
        glDetachShader(program, vs)
        glDetachShader(program, fs)
        glDeleteShader(vs)
        glDeleteShader(fs)

        val stacks = MemoryStack.stackPush()
        val renderData = stacks.malloc(colors.size * 1 + positions.size * 4)
        for (i in 0 until 6) {
            renderData.put((colors[i * 4] and 0xFF).toByte()) // unsigned byte
            renderData.put((colors[i * 4 + 1] and 0xFF).toByte())
            renderData.put((colors[i * 4 + 2] and 0xFF).toByte())
            renderData.put((colors[i * 4 + 3] and 0xFF).toByte())
            renderData.putFloat(positions[i * 4])
            renderData.putFloat(positions[i * 4 + 1])
        }
        renderData.flip()
        buffer = glGenBuffers()
        glBindBuffer(GL_ARRAY_BUFFER, buffer)
        glBufferStorage(GL_ARRAY_BUFFER, 72L, 0)
        glBufferSubData(GL_ARRAY_BUFFER, 0L, renderData)
        stacks.pop()

        glUseProgram(program)
        vertex = glGenVertexArrays()
        glBindVertexArray(vertex)
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(0, 2, GL_FLOAT, false, 4, 0)
        glEnableVertexAttribArray(1)
        glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, 0, 0)
    }

    override fun resume() {
        super.resume()
        glUseProgram(program)
        glBindBuffer(GL_ARRAY_BUFFER, buffer)
        glBindVertexArray(vertex)
        glEnableVertexAttribArray(0)
        glEnableVertexAttribArray(1)
    }

    override fun update(): Boolean {
        super.update()
        glDrawArrays(GL_TRIANGLES, 0, 6)
        return false
    }

    override fun stop() {
        super.stop()
        glDisableVertexAttribArray(0)
        glDisableVertexAttribArray(1)
        glBindVertexArray(0)
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glUseProgram(0)
    }

    override fun terminal() {
        glDeleteVertexArrays(vertex)
        glDeleteBuffers(buffer)
        glDeleteProgram(program)
    }
}

val goraudVertexShader = """
#version 400 core

layout( location = 0 ) in vec4 vPosition;
layout( location = 1 ) in vec4 vColor;

out vec4  color;

void main() {
    color = vColor;
    gl_Position = vPosition;
}
""".trimIndent()

val goraudFragmentShader = """
#version 400 core

in  vec4 color;
out vec4 fColor;

void main() {
    fColor = color;
}
""".trimIndent()